<template>
	<el-form
		class="mg-6"
		style="width: 98%"
		ref="formRef"
		size="default"
		autocomplete="off"
		v-bind="$attrs"
		v-loading="loading"
		element-loading-background="rgb(245 245 245 / 80%)"
		:element-loading-text="loadingText"
		:model="formMod"
		status-icon
		@keyup.enter.native="handleEnterSubmit"
	>
		<el-row :gutter="20">
			<el-col :span="item.span || 4" :xs="24" v-for="item in formColumn" :style="{ display: !displaySet(item) || item.formDisplay ? 'none' : '' }">
				<el-form-item
					:prop="item.prop"
					:rules="!displaySet(item, item.rules) || !showRules ? [] : item.rules"
					:style="{ display: 'flex', flexFlow: flexFlow(item, $attrs) }"
				>
					<template #label>
						<div class="flex align-center">
							<div class="fc">
								<span>{{ item.label }}</span>
								<span v-if="item.labelTip" class="text-tag fc">{{ item.labelTip }}</span>
							</div>
							<div>
								<el-tooltip effect="dark" v-if="item.tip" :content="item.tip" placement="top">
									<icon-info theme="outline" />
								</el-tooltip>
								<slot v-if="!!slots[item.prop + 'FormLabel']" :name="item.prop + 'FormLabel'" :row="item" :model="formMod"> </slot>
							</div>
						</div>
					</template>
					<slot v-if="!!slots[item.prop + 'Form']" :name="item.prop + 'Form'" :row="item" :model="formMod"> </slot>
					<template v-else>
						<component
							style="width: 100%"
							:required="item.required"
							:disabled="isDisbaled(item, formMod)"
							:is="typeComm[item.type] || ElInput"
							:fileLabel="item.propName"
							:name="item.prop"
							:prop="item.prop"
							v-model="formMod[item.prop]"
							v-model:modelName="formMod[item.propName]"
							v-model:modelOther="formMod[item.propOther]"
							v-bind="item"
							:placeholder="getPlaceholder(item)"
							@change="(event) => onChange(event, item, formMod[item.prop])"
						>
							<template v-slot:prepend v-if="item.prepend">
								<span class="f14"> {{ item.prepend }}</span>
							</template>
							<template v-slot:append v-if="item.append">
								<span class="f14"> {{ item.append }}</span>
							</template>
							<optionPage v-if="item.dicData" :type="item.type" :dicData="item.dicData"></optionPage>
						</component>
					</template>
				</el-form-item>
			</el-col>
			<el-col :span="inline ? 6 : 24" v-if="showBtn" :xs="24">
				<el-form-item>
					<div class="fc w-100">
						<el-button type="primary" :disabled="loading" @click="onSubmit()">
							<el-icon class="mr4">
								<icon-search v-if="inline" theme="outline" />
								<icon-check-one v-else theme="outline" />
							</el-icon>
							{{ inline ? '搜索' : submitBtnText }}
						</el-button>
						<el-button class="ap-btn" v-if="showReset" @click="onReset(formRef)">
							<el-icon class="mr4">
								<icon-redo theme="outline" />
							</el-icon>
							{{ inline ? '重置' : backBtnText }}
						</el-button>
						<slot name="btn" :model="formMod"></slot>
					</div>
				</el-form-item>
			</el-col>
			<el-col :span="24">
				<slot></slot>
			</el-col>
		</el-row>
	</el-form>
</template>

<script lang="ts" setup>
import optionPage from './option.vue'
import { getComponentCollecte, columnType } from '../../hooks/index'
import { useSlots } from 'vue'
import { ElInput, ElNotification } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
const typeComm: Object = getComponentCollecte()

type Props = {
	modelValue?: any
	model?: Object
	prop?: string
	rules?: FormRules
	column?: any
	listType?: 'text' | 'picture' | 'picture-card'
	backBtnText?: string
	submitBtnText?: string
	showBtn?: boolean
	showReset?: boolean
	inline?: boolean
	showRules?: boolean
	loadingText?: string
	rowKey?: string
}
const props = withDefaults(defineProps<Props>(), {
	dataType: 'string',
	showBtn: true,
	showReset: true,
	inline: false,
	showRules: true,
	backBtnText: '返回',
	submitBtnText: '提交',
	loadingText: '处理中...',
	rowKey: 'id',
})
const emit = defineEmits(['submit', 'reset', 'change', 'update:modelValue'])
const slots = useSlots()
const formRef: any = ref<FormInstance>()
const loading = ref(false)
let formMod: any = ref({})
let formColumn = ref(props.column || [])

// 判断选项是否禁用
const isDisbaled = (item, model) => {
	const isEdit = model[props.rowKey] ? true : false
	return (isEdit && item.editDisabled) || (!isEdit && item.addDisabled) || item.disabled ? true : false
}

const getPlaceholder = (item) => {
	if (item.placeholder) {
		return item.placeholder
	} else if (['remoteSelect', 'select', 'date', 'AplidAreaSelect'].includes(item.type)) {
		return `请选择${item.label}`
	} else {
		return `请输入${item.label}`
	}
}
const onChange = (e, item, value) => {
	emit('change', formMod, item, e)
	emit('update:modelValue', formMod.value)
	item.change && item.change(e, formMod.value, value)
	if (!formRef.value) return
	formRef.value.clearValidate([item.prop])
}

const displaySet: any = (item) => {
	if (item.editDisplay == false && formMod.value[props.rowKey]) {
		return false
	}
	const ruleItem = controlRule.value[item.prop] || {}

	if (ruleItem.hasOwnProperty('display')) {
		return ruleItem?.display
	} else {
		return item.display ==false?false:true 
	}
}
const onSubmit = () => {
	return new Promise((resolve, reject) => {
		formRef.value.validate((valid, val) => {
			if (valid) {
				loading.value = true
				emit('submit', formMod.value, () => {
					loading.value = false
				})
				resolve(formMod.value)
			} else {
				loading.value = false
				const obj = Object.keys(val)
				formRef.value.scrollToField(obj[0])
				ElNotification({
					title: '提示',
					message: '请将必填项填写完整',
					type: 'warning',
				})
				reject('erro')
			}
		})
	})
}
const onReset = () => {
	loading.value = false
	formMod.value = {}
	if (!formRef.value) return
	formRef.value.resetFields()
	emit('reset', formMod.value)
}
const handleEnterSubmit = () => {
	// const ueditor = props.column.filter(col => col.type == 'ueditor')
	if (props.inline && props.showBtn) {
		onSubmit()
	}
}
const controlRule = ref({})
const formateControl = () => {
	props.column.map((item) => {
		if (!item.control) {
			return
		}
		const control: any = item.control(formMod.value[item.prop], formMod.value)

		controlRule.value = {
			...controlRule.value,
			...control,
		}
		const propArr: any = Object.keys(control)
		if (propArr.length > 0) {
			propArr.map((p) => {
				const findIndex = formColumn.value.findIndex((c) => c.prop == p)
				const colItem = formColumn.value[findIndex]
				if (control[p] && control[p].hasOwnProperty('required')) {
					if (colItem?.rules) {
						formColumn.value[findIndex].rules.some((item) => {
							if (item.hasOwnProperty('required')) {
								item.required = control[p].required
							}
							if (item.hasOwnProperty('pattern')) {
								item.pattern = parseJson(item.pattern) || item.pattern
							}
						})
					}
				}
			})
		}
	})
}
// 处理转字符串的正则校验
const parseJson = (jsonStr) => {
	const _eval = (fn) => {
		const Fun = Function
		return new Fun('return ' + fn)()
	}

	if (jsonStr && typeof jsonStr == 'string') {
		return JSON.parse(jsonStr, (k, v) => {
			try {
				// 将正则字符串转成正则对象
				if (_eval(v) instanceof RegExp) {
					return _eval(v)
				}
			} catch (e) {
				// nothing
			}

			return v
		})
	}
}
watch(
	() => props.modelValue,
	(val) => {
		const tempVal = props.model ?? val ?? {}
		// 提取默认值
		const tempDefault = {}
		let copyFormColumn = props.column || []
		copyFormColumn.forEach((item: any) => {
			if (item.defaultValue || item.defaultValue === 0) tempDefault[item.prop] = tempVal[item.prop] ?? item.defaultValue
		})
		const modelValue = {
			...tempVal,
			...tempDefault,
		}

		setTimeout(() => {
			formMod.value = modelValue
			// 获取所有的控制
			if (props.column && props.column.length > 0) {
				formateControl()
			}
		}, 0)
	},
	{
		immediate: true,
		deep: true,
	}
)

const flexFlow = (item, config) => {
	if (item.labelPosition) {
		return item.labelPosition == 'top' ? 'column' : 'row'
	}
	{
		return config.labelPosition == 'top' ? 'column' : config.labelPosition
	}
}

onMounted(() => {
	formMod.value = props.model ?? props.modelValue ?? {}
})

defineExpose({
	onReset,
	onSubmit,
})
</script>

<style scoped lang="scss">
:deep(.el-input__wrapper) {
	width: 100%;
}

:deep(.el-form-item__label) {
	display: flex !important;
	justify-content: flex-start;
}
.text-tag {
	background: rgba(0, 82, 217, 0.1);
	font-family: 'Microsoft YaHei';
	font-weight: 400;
	font-size: 14px;
	color: #0052d9;
	padding: 1px 10px;
	border-radius: 4px;
	margin-left: 12px;
}
</style>
